﻿using System;
using System.Collections.Generic;
using System.IO;
using Nini.Config;
using Sync.Log;

namespace Sync.User
{
    /// <summary>
    /// This class creates a .ini file for storing user preferences.
    /// Configs are stored as [name]
    /// Keys are stored as variables: variableName="thishere"
    /// </summary>
    public static class Preferences
    {
        public static string FullFilePath { get; private set; }
        public static IniConfigSource IniConSource { get; private set; }

        /// <summary>
        /// Tries to access the file. If no file is found, throws Arguement exception.
        /// </summary>
        /// <param name="filePath">Path of the .ini file you would like to modify.</param>
        /// <param name="fileName">Name of the .ini file you would like to modify.</param>
        public static void UseFile(string filePath, string fileName)
        {
            FullFilePath = Path.Combine(filePath, fileName);
            if (String.IsNullOrEmpty(Path.GetExtension(FullFilePath)))
                FileLog.LogMessage("No file exstention found for " + fileName, LogType.Warning);
            if (!System.IO.File.Exists(FullFilePath))
            {
                FileLog.LogMessage("File not found at: " + FullFilePath + ". Created a new file at this location.", LogType.Warning);
                System.IO.File.Create(FullFilePath).Close();
            }
            IniConSource = new IniConfigSource(FullFilePath) { CaseSensitive = true };
        }

        /// <summary>
        /// Creates a new file at the specified path. If one is not found.
        /// </summary>
        /// <param name="filePath">Path of the .ini file you would like to modify.</param>
        /// <param name="fileName">Name of the .ini file you would like to modify.</param>
        public static void CreateiniFile(string filePath, string fileName)
        {
            FullFilePath = Path.Combine(filePath, fileName);
            if (!System.IO.File.Exists(FullFilePath))
            {
                System.IO.File.Create(FullFilePath).Close();
                FileLog.LogMessage(
                    "File at " + Path.GetFullPath(FullFilePath) + " is not Found. Creating new " + fileName + " file.",
                    LogType.Warning);
                IniConSource = new IniConfigSource(FullFilePath) { CaseSensitive = true };
            }
            else
            {
                throw new Exception("There is already a file by that name.");
            }
        }

        /// <summary>
        /// Adds a Config value to the current settings file. Throws ArgumentException.
        /// [name]
        /// </summary>
        /// <param name="name">config name to list key values under.</param>
        public static void AddConfig(string name)
        {
            try
            {
                IniConSource.AddConfig(name);
                FileLog.LogMessage("Added config [" + name + "] successfully.");
            }
            catch (ArgumentException e)
            {
                FileLog.LogMessage("Could not add config [" + name + "] to " + Path.GetFullPath(FullFilePath) + "Already Exists", LogType.Error);
            }
            IniConSource.Save(FullFilePath);
        }

        /// <summary>
        /// Gets the keys listed under the current IniConfigSource.
        /// </summary>
        /// <param name="configName">Config name.</param>
        /// <returns>IEnumerable of type string</returns>
        public static IEnumerable<string> GetKeys(string configName)
        {
            return IniConSource.Configs[configName].GetKeys();
        }

        /// <summary>
        /// Changes the source of IniConSource to another .ini file. Throws FileNotFoundException.
        /// </summary>
        /// <param name="filePath">Path of the .ini file you would like to modify.</param>
        /// <param name="fileName">Name of the .ini file you would like to modify.</param>
        public static void ChangeSource(string filePath, string fileName)
        {
            FullFilePath = Path.Combine(filePath, fileName);
            if (String.IsNullOrEmpty(Path.GetExtension(FullFilePath)))
                FileLog.LogMessage("No file exstention found for " + fileName, LogType.Warning);
            try
            {
                IniConSource.Load(FullFilePath);
                FileLog.LogMessage("Source was changed successfully to " + Path.GetFullPath(FullFilePath));
            }
            catch (FileNotFoundException)
            {
                FileLog.LogMessage(
                    "File at " + Path.GetFullPath(FullFilePath) + " is not found.",
                    LogType.Error);
                throw new FileNotFoundException("File at " + Path.GetFullPath(FullFilePath) + " is not found.");
            }
        }

        /// <summary>
        /// Adds a key under the specified configName. Throws NullReferenceException if nothing is found.
        /// </summary>
        /// <param name="configName">anme of the config to add a key under</param>
        /// <param name="keyName">Key name</param>
        /// <param name="value">parameter for that specified key name</param>
        public static void AddKey(string configName, string keyName, object value)
        {
            try
            {
                IniConSource.Configs[configName].Set(keyName, value);
                FileLog.LogMessage( keyName + " under [" + configName + "] was added with the value of " + value);
            }
            catch(NullReferenceException)
            {
                FileLog.LogMessage(keyName + " under [" + configName + "] could not be added with the value of " + value, LogType.Error);
                throw new NullReferenceException(keyName + " under [" + configName + "] could not be added with the value of " + value);
            }
            IniConSource.Save(FullFilePath);
        }

        /// <summary>
        /// Determins if the specified configName is a valid Config in the Setup.ini File.
        /// </summary>
        /// <param name="configName">Name of the config you want to know if exsists</param>
        /// <returns>bool</returns>
        public static bool Contains(string configName)
        {
            return IniConSource.Configs.Contains(configName);
        }
    }
}